﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Streamsol.Crm;
using Microsoft.Crm.SdkTypeProxy.Metadata;
using Microsoft.Crm.Sdk.Metadata;
using System.ComponentModel;
using Microsoft.Crm.Sdk;

namespace Streamsol.Crm.XrmDevelopmentToolkit
{
    public static class MetadataHelper
    {
        /// <summary>
        /// Constructs a Universal Entity List. You may also use the extension method on the CrmServive, BuildUniversalEntityList
        /// </summary>
        /// <param name="crmEntities"></param>
        /// <param name="metaServiceUrl"></param>
        /// <param name="orgName"></param>
        public static UniversalEntityList BuildUniversalEntityList(this MetadataService metadataService, BusinessEntityCollection crmEntities)
        {
            // Get the name of the entity
            // Note: We have to convert this to lower because RetrieveEntityMetadata expects the schema name
            string entityName = crmEntities.EntityName;
            entityName = entityName.ToLower(System.Globalization.CultureInfo.CurrentCulture);

            // Get the metadata for the currently list's entity
            // This metadata is used to create a "Property Descriptor Collection"
            RetrieveEntityRequest mdRequest = new RetrieveEntityRequest()
            {
                EntityItems = EntityItems.EntityOnly | EntityItems.IncludeAttributes,
                LogicalName = entityName,
                RetrieveAsIfPublished = true
            };

            // Execute the request
            RetrieveEntityResponse entityResponse = (RetrieveEntityResponse)metadataService.Execute(mdRequest);

            EntityMetadata entityData = entityResponse.EntityMetadata;

            // Cache locals
            PropertyDescriptorCollection columnDescriptors = UniversalEntity.CreatePropertyDescriptorCollection(entityData.Attributes);
            List<BusinessEntity> entities = crmEntities.BusinessEntities;

            return new UniversalEntityList(columnDescriptors, entities);
        }

        /// <summary>
        /// Constructs a Universal Entity List. You may also use the extension method on the Crm Service, BuildUniversalEntityList
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="metadataService"></param>
        /// <param name="entities"></param>
        /// <returns></returns>
        public static UniversalEntityList BuildUniversalEntityList<TEntity>(this MetadataService metadataService, IEnumerable<TEntity> entities)
               where TEntity : BusinessEntity, new()
        {
            return BuildUniversalEntityList(metadataService, entities.ToBusinessEntityCollection());
        }

        public static BusinessEntityCollection ToBusinessEntityCollection<TEntity>(this IEnumerable<TEntity> entities)
            where TEntity : BusinessEntity, new()
        {
            return new BusinessEntityCollection()
            {
                EntityName = typeof(TEntity).Name,
                BusinessEntities = entities.Cast<BusinessEntity>().ToList()
            };
        }

        /// <summary>
        /// Gets the attribute metadata for a specified attribute.
        /// </summary>
        /// <typeparam name="TAttributeMetadata">The type of attributemetadata to retrieve, e.g PicklistAttributeMetadata</typeparam>
        /// <param name="metadataService"></param>
        /// <param name="entityName">The name of the entity.</param>
        /// <param name="picklistAttributeName">The name of the attribute.</param>
        /// <returns>A <typeparamref name="TAttributeMetadata"/>.</returns>
        public static TAttributeMetadata GetAttributeMetadata<TAttributeMetadata>(this MetadataService metadataService, string entityName, string picklistAttributeName)
            where TAttributeMetadata : AttributeMetadata
        {
            RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest()
            {
                EntityLogicalName = entityName,
                LogicalName = picklistAttributeName,
                RetrieveAsIfPublished = true
            };
            var attributeResponse = (RetrieveAttributeResponse)metadataService.Execute(attributeRequest);

            return (TAttributeMetadata)attributeResponse.AttributeMetadata;
        }

        /// <summary>
        /// Gets the display names and values of a picklist field in CRM.
        /// </summary>
        /// <param name="metadataService"></param>
        /// <param name="entityName">The name of the entity.</param>
        /// <param name="picklistAttributeName">The name of the attribute.</param>
        /// <returns>An IEnumerable sequence of XrmPicklistInfo.</returns>
        public static IEnumerable<XrmPicklistInfo> GetPicklistValues(this MetadataService metadataService, string entityName, string picklistAttributeName)
        {
            var picklistMetadata = metadataService.GetAttributeMetadata<PicklistAttributeMetadata>(entityName, picklistAttributeName);

            foreach (Option o in picklistMetadata.Options)
                yield return new XrmPicklistInfo(o.Label.UserLocLabel.Label, o.Value.Value);
        }

    }
}
